<?php

/**
 * This file is part of Switcher.
 * 
 * Switcher is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Switcher is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Switcher. If not, see <http://www.gnu.org/licenses/>.
 * 
 * @license http://www.opensource.org/licenses/gpl-3.0.html GPL-3.0
 */

namespace switcher\config;

/**
 * This class provides all information needed to serve a view to the user. It
 * embeds the corresponding <b>Renderer</b> and <b>Controller</b>, the declared
 * HTTP parameters and allowed HTTP methods.
 * 
 * <p>This class shouldn't be used. Instances are built by the <b>Config</b>
 * class and consumed by the <b>Switcher</b> class.</p>
 * 
 * @author Dri <switcher.framework@gmail.com>
 * @license http://www.opensource.org/licenses/gpl-3.0.html GPL-3.0
 * @package switcher\config
 * @since 1.0.0
 * @see switcher\Switcher
 * @see switcher\config\Config
 */
final class View
{
	/**
	 * The path information for the view. It is an associative array with the following keys :
	 * <ul>
	 *  <li>pattern (string) : the declared pattern</li>
	 *  <li>matches (array) : the parts matching regexp groups or shell wildcards</li>
	 *  <li>regexp (bool) : indicates whether the pattern is a regular expression</li>
	 * </ul>
	 * @var array
	 * @see switcher\utils\FileHelper::match()
	 */
	public $path;
	
	/**
	 * The allowed HTTP methods.
	 * @var array
	 */
	public $methods;
	
	/**
	 * Indicates whether the request should use AJAX (yes|no|optional).
	 * @var string
	 * @default 'no'
	 */
	public $ajax = 'no';
	
	/**
	 * The required and optional HTTP GET parameters.
	 * @var array
	 */
	public $getParameters;
	
	/**
	 * The required and optional HTTP POST parameters.
	 * @var array
	 */
	public $postParameters;
	
	/**
	 * The renderer.
	 * @var switcher\renderers\Renderer
	 */
	public $renderer;
	
	/**
	 * The controller.
	 * @var switcher\controllers\Controller
	 */
	public $controller;
	
	/**
	 * The controller's action.
	 * @var string
	 */
	public $action;
	
	/**
	 * Check if a request is valid according to its declaration.
	 * 
	 * @throws switcher\exceptions\BadRequestException If the current HTTP method is not supported
	 * @throws switcher\exceptions\NotFoundException If a parameter is missing or unexpected
	 */
	public function checkRequest()
	{
		$this->checkRequestMethod();
		$this->checkAjax();
		$this->checkParameters('get', $_GET);
		
		if ($requestMethod == 'post')
		{
			$this->checkParameters('post', $_POST);
		}
	}
	
	/**
	 * Check if the request method is allowed for the view.
	 * 
	 * @throws switcher\exceptions\BadRequestException If the current HTTP method is not supported
	 */
	private function checkRequestMethod()
	{
		$allowedMethods = $this->methods;
		$requestMethod = \switcher\utils\HttpHelper::getRequestMethod();
		
		if ( !in_array($requestMethod, $allowedMethods, true) )
		{
			throw new \switcher\exceptions\BadRequestException('HTTP method not allowed : ' . $requestMethod);
		}
	}
	
	/**
	 * Check if the type of request (classic or AJAX) is allowed for the view.
	 * 
	 * @throws switcher\exceptions\BadRequestException If the resquest type is not supported
	 */
	private function checkAjax()
	{
		if ($this->ajax == 'optional')
		{
			return;
		}
		
		$isAjax = \switcher\utils\HttpHelper::isAjaxRequest();
		$shouldBeAjax = $this->ajax == 'yes';
		
		if ($isAjax != $shouldBeAjax)
		{
			throw new \switcher\exceptions\BadRequestException('Unauthorized request type');
		}
	}
	
	/**
	 * Test actual parameters against declared parameters. If get/post parameters don't match
	 * expected names, it is assumed for now that this is an innocent mistake. So instead of
	 * throwing a BadRequestException, a NotFoundException is throwed.
	 * 
	 * @param string $method The parameters type (GET or POST)
	 * @param array $params The actual parameters of the request
	 * @throws switcher\exceptions\NotFoundException If a parameter is missing or unexpected
	 */
	private function checkParameters($method, $params)
	{
		// get declarations
		$declaredParams = $this->{$method . 'Parameters'};
		
		// check existence of each declared param
		foreach ($declaredParams as $name => $optional)
		{
			// if the param exists
			if (isset( $params[$name] ) || $optional)
			{
				unset( $params[$name] ); // remove it from the array
			}
			else
			{
				throw new \switcher\exceptions\NotFoundException('Missing ' . $method . ' parameter : ' . $name);
			}
		}
		
		// TODO filter params ?
		
		// unwanted parameters not allowed
		if (count($params) > 0)
		{
			$unexpected = implode( ', ', array_keys($params) );
			throw new \switcher\exceptions\NotFoundException('Unexpected ' . $method . ' parameters : ' . $unexpected);
		}
	}
}

?>